home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Medal Software 2
/
Gold Medal Software Volume 2 (Gold Medal) (1994).iso
/
prog
/
asm_n_z.arj
/
TSRSH.ASM
< prev
next >
Wrap
Assembly Source File
|
1987-02-02
|
27KB
|
1,100 lines
PAGE 60,132
TITLE Ram-Resident Program Shell, Preliminary Version (Lesson 2)
SUBTTL Date 02-02-87 -- Tutorial for Microsoft Forum Version 0.03
;-----------------------------------------------------------------------------
; Ram-Resident Program Shell
;
;
;The software, documentation and source code are:
;
; (C) Copyright 1986, 1987
; Chip Rabinowitz
; All Rights Reserved
;
; 51 East Rogues Path
; Huntington Station NY 11746
; Assistant SysOp, Microsoft Forum, Compuserve PPN 76703,350
;
;
;COPYRIGHT NOTICE AND WARRANTY INFORMATION
;-----------------------------------------
;
;This document ("the source code"), other accompanying written and disk-based
;notes and specifications ("the documentation"), and all referenced and related
;program files accompanying the source code and the documentation ("the
;software") are copyrighted by Chip Rabinowitz.
;
;This program has been uploaded to Compuserve as part of a Tutorial in how
;to write Terminate-But-Stay-Resident programs, being conducted on
;Compuserve's Microsoft Special Interest Group during early 1987/
;
;This code (and all other code uploaded by the Copyright Holder as a
;part of this TSR Tutorial) may be used with the following restrictions:
;
;(1) If all or part of this code is used as part of a software package of
;ANY kind, the following acknowledgement must be used in the Documentation
;accompanying said package:
;
; 'Parts of the Resident Program Management for this Product are'
; 'Copyright (C) 1986, 1987 by Chip Rabinowitz, and are incorporated'
; 'into this product courtesy of the Ringmaster Development Team'
;
;(2) If all or part of this code is used as part of a software package that
;is placed in the public domain, no further restrictions apply.
;
;(3) If all or part of this code is used as part of a software package that
;is being distributed as 'shareware', a one-time-only donation of $10 will be
;accepted for the express purpose of continuing research into TSR standards.
;Note that this is a voluntary contribution, and should be sent to the
;Ringmaster Development Team at the address printed above.
;
;(4) If all or part of this code is used as part of a software package that
;will be distributed as a commercial product, a one-time-only payment of
;$25 will be accepted the express purpose of continuing research into TSR
;standards. Note that in THIS CASE ONLY, this is not a voluntary
;contribution. Commercial Developers are REQUIRED to make payment prior to
;incorporating these routines into their product.
;
;No copy of the source code may be distributed or given away without the
;accompanying documentation; and this notice must not be removed.
;
;There is no warranty of any kind associated with this software, and the
;copyright owner is not liable for damages of any kind. By using this
;software, you agree to this.
;
;
XON equ 11h
XOFF equ 13h
TRUE equ 1
FALSE equ 0
CR equ 0dh
LF equ 0ah
TAB equ 9
HOTKEYON equ 01h ;hot key pressed
SHIFTSON equ 02h ;shift states match
TSRACTIVE equ 04h ;tsr is running in foreground
INT28ACTIVE equ 08h ;INT28 routine is running in background
KB_DATA equ 60h
KB_CTL equ 61h
KB_FLG1 equ 17h
KB_FLG2 equ 18h
BIOS_DATA equ 40h
code segment para public 'CODE'
org 100h
assume cs:code, ds:code, es:code
start: jmp begin
db 1bh,'[2J'
cpyrt db 'Ram-Resident Program Shell, Preliminary Version (Lesson 2)',
db CR,LF,LF
db 'Copyright (C) 1986, 1987 Chip Rabinowitz',
db CR,LF,'All Rights Reserved',CR,LF,LF,'$'
hello db 'Hello World!',CR,LF,'$'
bad_dos_msg db 'Incompatible DOS version .... Aborting!',07h,CR,LF,'$'
tsr_parms:
PSP dw ? ;PSP of TSR
OLDPSP dw ? ;location to save current PSP
DTA dd ? ;DTA of TSR
OLDDTA dd ? ;location to save current DTA
DSEG dw ? ;TSR's Data Segment
SSEG dw ? ;TSR's Stack Segment ....
SPTR dw 0fffeh ;.... and Stack Pointer
ISSEG dw 0 ;interrupted SS ...
ISPTR dw 0 ;..... and SP
SHIFTST db 0 ;Shift State to Activate
HOTKEY db 0ffh ;scan code to activate
STATUS dw 0 ;current status words
POPUP dd 0 ;far pointer to popup routine
intflags db 0
ININT13 equ 04h ;Bios disk interrupt
ININT21 equ 08h ;DOS interrupt
dosversion db 0 ;current version of DOS
waitcount db 0 ;wait to activate count
indosflag dd 0 ;Pointer to INDOS flag
doscriterr dd 0 ;Pointer to DOS Critical Error Flag
dossseg dw 0 ;pointer to dos stack segment
dossptr dw 0 ;pointer to dos stack pointer
dossize dw 0 ;dos stack size
dos21funcs label byte
db 0, 0, 0, 0, 0, 0, 0, 0 ;0-7
db 0, 0, 0, 0, 0, 0ffh, 0ffh, 0ffh ;8-f
db 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh ;10-17
db 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh ;18-1f
db 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0, 0ffh ;20-27
db 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0 ;28-2f
db 0ffh, 0, 0, 0, 0, 0, 0ffh, 0ffh ;30-37
db 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh ;38-3f
db 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh ;40-47
db 0, 0, 0, 0, 0ffh, 0, 0ffh, 0ffh ;48-4f **
db 0, 0, 0, 0, 0ffh, 0, 0ffh, 0ffh ;50-57
db 0, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0, 0 ;58-5f
db 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh ;60-67
;
; ***************************************************************************
; These are the bios interrupt vectors
;
BIOSI8 equ 08h ;Bios Timer interrupt
BIOSI9 equ 09h ;BIOS Hardware Keyboard interrupt
BIOSIB equ 0Bh
BIOSIC equ 0Ch
BIOSI10 equ 10h
BIOSI13 equ 13h ;Bios Disk interrupt
BIOSI14 equ 14h
BIOSI15 equ 15h
BIOSI16 equ 16h ;Bios Keyboard interrupt
BIOSI17 equ 17h
BIOSI1C equ 1Ch
DOSI21 equ 21h ;DOS service router interrupt
DOSI28 equ 28h ;DOS Idle interrupt
DOSI33 equ 33h ;mouse interrupt
BIOSI1B equ 1Bh
DOSI23 equ 23h
DOSI24 equ 24h
;
oldint8 dd 0 ;BIOS Hardware Timer Interrupt
db BIOSI8
dw offset newint8 ;replacement vector
oldint9 dd 0 ;BIOS Hardware Keyboard Interrupt
db BIOSI9
dw offset newint9 ;replacement vector
oldint13 dd 0 ;BIOS Disk Interrupt
db BIOSI13
dw offset newint13 ;replacement vector
oldint16 dd 0 ;BIOS Software Keyboard Interrupt
db BIOSI16
dw offset newint16 ;replacement vector
oldint21 dd 0 ;DOS Services Interrupt
db DOSI21
dw offset newint21 ;replacement vector
oldint28 dd 0 ;DOS Idle Interrupt
db DOSI28
dw offset newint28 ;replacement vector
oldint1B dd 0 ;control-C vector
db BIOSI1B
dw offset intret ;replacement vector
oldint23 dd 0 ;control-C vector
db DOSI23
dw offset intret ;replacement vector
oldint24 dd 0 ;critical error vector
db DOSI24
dw offset newint24 ;replacement vector
;
; ***************************************************************************
; Function to restore interrupts.
;
; If AX=0, this function does popup-interrupts (1B, 23 and 24)
; If AX=anything else, this function does initial interrupts
;
restore_int proc near
push ds
push ax
push dx
push si
push di
push cx
mov di,7 ;7 bytes per structure
or ax,ax
jnz restore1
mov cx,3 ;three times through
mov si,offset oldint1B ;start at table beginning
jmp restore_loop
restore1:
mov cx,06h ;six interrupts!
mov si,offset oldint8 ;top of table
restore_loop:
push cx
push di ;save structure size
push ds
mov al,4[si] ;interrupt number
mov dx,[si] ;IP of interrupt vector
mov ds,2[si] ;CS of interrupt vector
mov ah,25h ;set interrupt vector function
int 21h
pop ds
xor ax,ax ;clear this entry from table
mov [si],ax ;so it shows not used
mov 2[si],ax
pop di ;get size back
add si,di ;do it again
pop cx
loop restore_loop
pop cx
pop di
pop si
pop dx
pop ax
pop ds
ret
restore_int endp
;
; ***************************************************************************
; Function to set interrupts.
;
; If AX=0, this function does popup-interrupts (1B, 23 and 24)
; If AX=anything else, this function does initial interrupts
;
setup_int proc near
push es
push ax
push bx
push dx
push di
push si
push cx
mov di,7 ;7 bytes per structure
or ax,ax
jnz setup1
mov cx,3 ;three times through
mov si,offset oldint1B ;start at table beginning
jmp setup_loop
setup1:
mov cx,06h ;six interrupts!
mov si,offset oldint8 ;top of table
setup_loop:
push cx
push di ;save structure size
; push ds
mov ax,[si] ;check for value
or ax,ax ;if not zero, next one
jnz setup2
mov al,4[si] ;interrupt number
mov ah,35h ;get interrupt vector function
int 21h
; pop ds
mov [si],bx ;save IP
mov 2[si],es ;save CS
mov al,4[si] ;interrupt number
;DS already contains correct segment
mov dx,5[si] ;IP of interrupt vector
mov ah,25h ;set interrupt vector function
int 21h
setup2:
pop di ;get size back
add si,di ;do it again
pop cx
loop setup_loop
ex_set:
pop cx
pop si
pop di
pop dx
pop bx
pop ax
pop es
ret
setup_int endp
setdta macro ddptr
push ds
mov ax,1a00h ;Function used to get current DTA address }
mov dx,word ptr ddptr ;Offset of DTA returned }
mov ds,word ptr ddptr+2 ;Segment of DTA returned by DOS }
int 21h ;Execute MSDos function request }
pop ds
endm
getdta macro ddptr
push es
mov ax,2f00h ;Function used to get current DTA address }
int 21h ;Execute MSDos function request }
mov word ptr ddptr+2,es ;Segment of DTA returned by DOS }
mov word ptr ddptr,bx ;Offset of DTA returned }
pop es
endm
;
; ***************************************************************************
; S E T P S P
;
; A bug in DOS 2.0, 2.1, causes DOS to clobber its standard stack }
; Then the PSP get/set functions are issued at the DOS prompt. The }
; following checks are made, forcing DOS to use the "critical" }
; stack when the TSR enters at the INDOS level. }
;
; BX contains the PSP segment to set
;
setpsp proc near
call checkindos ;If Version < 3, and INDOS,...
jz do_set_psp
mov byte ptr es:[di],0ffh ;set critical flag
do_set_psp:
mov ax,5000h ;set PSP* function
;BX already holds segment
int 21h ;DOS function request
call checkindos ;If Version < 3, and INDOS,...
jz set_out
mov byte ptr es:[di],0h ;set critical flag
set_out:
ret
setpsp endp
;
; ***************************************************************************
; G E T P S P
;
; A bug in DOS 2.0, 2.1, causes DOS to clobber its standard stack }
; Then the PSP get/set functions are issued at the DOS prompt. The }
; following checks are made, forcing DOS to use the "critical" }
; stack when the TSR enters at the INDOS level. }
;
; The PSP Segment is returned in BX
;
getpsp proc near
call checkindos ;If Version < 3, and INDOS,...
jz do_get_psp
mov byte ptr es:[di],0ffh ;set critical flag
do_get_psp:
mov ax,5100h ;get PSP function
int 21h ;DOS function request
;BX now holds PSP segment
call checkindos ;If Version < 3, and INDOS,...
jz get_out
mov byte ptr es:[di],0h ;clear critical flag
get_out:
ret
getpsp endp
;
; ***************************************************************************
; This routine checks the version of DOS in use, and returns the
; ZF=0 (Not zero) if version < 3.0, and INDOS is set. Internal function
; is called ONLY by getpsp and setpsp.
;
checkindos proc near
mov al,dosversion
cmp al,3 ;If Version is less than 3.0 ...
jge ok_ret
mov es,word ptr indosflag+2 ; ... and ...
mov di,word ptr indosflag
mov al,byte ptr es:[di]
or al,al ;INDOS is set ...
jz ok_ret
mov es,word ptr doscriterr+2; ... then ...
mov di,word ptr doscriterr
jmp fixit ;exit with not zero
ok_ret:
xor al,al ;set zero flag
fixit:
ret
checkindos endp
;
; ***************************************************************************
; Internal routine to establish addressibility of the data segment
;
dds proc near
push cs
pop ds
ret
dds endp
newint9 proc far
;NOTE: None of this pusing/popping is really necessary for THIS particular
;TSR, so I;ve commented it out.
;
; pushf
; cli
; push ds
; push es
; push ax
; push bx
; push cx
; push dx
; push di
; push si
; push cs
; pop ds
;internal INT9 processing here
;getkey_out:
; pop si
; pop di
; pop dx
; pop cx
; pop bx
; pop ax
; pop es
; pop ds
;out_9:
; popf
; cli
jmp dword ptr cs:oldint9
;
; ***************************************************************************
; This is the int return (IRET) dummy pointer
;
intret:
iret
;This routine will be used at some future point ... commented out for now.
;
;ignore_9:
; in al,60h
; push ax
; pop ax
; in al,61h
; mov ah,al
; or al,80h
; out 61h,al
; xchg ah,al
; out 61h,al
; mov al,20h
; out 20h,al
; pop ax
; jmp short out_9
newint9 endp
new_bios_flag db 0
newint16 proc far
start_again:
cmp ah,00 ;if char request,
je func00 ;loop for character
cmp ah,01 ;if character availability test
je func01 ;go check for char
push ax
and ah,10h ;test for extra bios
pop ax
jz gobios16
mov cs:new_bios_flag,10h
and ah,3
jmp short start_again
gobios16:
or ah,cs:new_bios_flag
jmp dword ptr cs:[oldint16]
;go to bios interrupt 16
func01:
push ds
push si
push di
call dds
func01A:
call keystat ;look at key buffer
pushf ;save return flags
jz fret01 ;return if no key
call hotcheck ;test for hot key
jnz fret01 ;not there
popf ;flags back for loop
jmp func01A ;it was a hot key -- skip it!
fret01:
mov new_bios_flag,0
popf ;flags back
pop di
pop si
pop ds
ret 2 ;return to user
func00:
push ds
push si
push di
call dds
func00A:
call keystat ;wait until character available
jz func00A ;loop it
call hotcheck ;test for a hot key
jz func00A ;it sure was -- start loop again
b_func0:
mov ah,0 ;get the next user key
or ah,new_bios_flag
pushf ;simulate it ...
call dword ptr cs:oldint16 ;do bios
func_out:
pushf ;save return flags
jmp fret01 ;restore and return
newint16 endp
;
; call the background task if no key is available
;
keystat proc near
;preserves all registers except
;AX,SI,DI,DS & flags
push cx
push bx
push ax
push ds
cld
mov ax,BIOS_DATA
mov ds,ax ;set data segment
mov si,KB_FLG1 ;set source
lodsw ;get the high and low bytes
pop ds
mov bx,ax ;save it away
pop ax
mov al,SHIFTST ;shift state check
or al,al ;is it zero?
jz sim_16 ;yes -- set flag for simulation
push bx ;save current flags
and bl,al ;mask bits
cmp al,bl ;are we the same?
pop bx
jne skip_16A ;nope -- next one
sim_16:
or word ptr STATUS,SHIFTSON ;set the flag
mov al,HOTKEY ;is this control block the last one?
or al,al
jnz short skip_16
or word ptr STATUS,HOTKEYON ;turn on hotkey flag
jmp short skip_16
skip_16A:
and word ptr STATUS,NOT SHIFTSON ;set the flag
skip_16:
mov ah,1 ;see if character is available
or ah,new_bios_flag
pushf ;simulate interrupt
call dword ptr cs:oldint16
jnz exit_161 ;got one
chkdos_161:
cld
push ds ;check if dos critical error in effect
push si
lds si,cs:doscriterr ;zero says dos is interruptable
lodsb ;$ff says dos is in a critical state
lds si,cs:indosflag ;if indos then int $28 issued by dos
or al,[si] ;so we dont have to.
;account for active interrupts
or al,cs:intflags ;any flags says we dont issue call
pop si ;to the background.
pop ds
cmp al,01 ;must be indos flag only
jg skip28 ;dos cannot take an interrupt yet
int 28h ;call dos idle function (background dispatch).
skip28:
xor ax,ax ;show no keycode available
exit_161:
pop bx
pop cx
ret
keystat endp
hotcheck proc near ;DI points to TSR Block character is from
;SI holds ID of TSR routine
push cx
push ax ;save character
push di
mov al,HOTKEY
or al,al
jz only_shift ;special case for shift-state only
cmp al,ah ;do scan codes match?
jne again_16H
only_shift:
push ax
mov ax,STATUS ;get TSR status flags
test ax,SHIFTSON ;are shift codes set?
jz again_16H1 ;nope -- try next one
or ax,HOTKEYON ;turn on hotkey flag
mov STATUS,ax ;put new flags back
pop ax
or al,al ;test for special case
pop di ;get back Block pointer
pop ax ;throwing this away
jz hot_out ;special case for flags only
b_func1:
mov ah,0 ;get rid of the character
or ah,new_bios_flag
pushf ;simulate interrupt
call dword ptr cs:oldint16 ;do bios
hot_out:
xor ax,ax ;set zero flag
jmp got_hot
again_16H1:
pop ax ;get rid of flag
again_16H:
mov al,0ffh
or al,al ;clear zero flag if set
pop di
pop ax ;get back keystroke
got_hot:
pop cx ;get back cx register
ret
hotcheck endp
newint8 proc far
pushf
push ds
push di
push cx ;save regs
push ax
call dds
mov ax,STATUS
test ax,HOTKEYON ;is hot-key flag set?
jz again_8_2
test ax,TSRACTIVE ;are we already running?
jnz again_8_2 ;yep -- next one
wait_8:
cmp waitcount,0 ;if waiting, check time
jnz wait2_8 ;decrement count
chkdos_8:
cld
push ds ;check if dos critical error in effect
push si
lds si,cs:doscriterr ;zero says dos is interruptable
lodsb ;$ff says dos is in a critical state
lds si,cs:indosflag ;add in second status byte
or al,[si]
or al,cs:intflags ;any flags says we're busy
pop si
pop ds
jnz wait1_8 ;we're busy -- set count & EXIT
call dopopup ;call the popup stuff
jmp end_8 ;and out we go
wait1_8:
mov waitcount,10h ;set the count
wait2_8:
dec waitcount
jz chkdos_8
again_8_2:
end_8:
pushf ;simulate interrupt ...
call dword ptr oldint8 ;do the original
pop ax ;get back registers
pop cx
pop di
pop ds
popf
exit_8:
iret
newint8 endp
newint28 proc far
pushf ;simulate interrupt ...
call dword ptr cs:oldint28 ;do the original
push ds
push di
push cx ;save regs
push ax
push cs
pop ds
again_28:
mov ax,STATUS ;get TSR status flags
test ax,HOTKEYON ;is hot-key flag set?
jz again_28_2
test ax,TSRACTIVE ;are we already running?
jnz again_28_2 ;yep -- next one
chkdos_28:
cld
push ds ;check if dos critical error in effect
push si
lds si,cs:doscriterr ;zero says dos is interruptable
lodsb ;$ff says dos is in a critical state
or al,cs:intflags ;any flags says we're busy
;NOTE: Indos flag is always set here!
; ... so don't have to check it!
pop si
pop ds
jnz end_28 ;we're busy-EXIT & try again next time
mov waitcount,0 ;clear waiting count and ...
call dopopup ;... call the popup stuff
jmp end_28 ;and out we go
again_28_2:
end_28:
pop ax ;get back registers
pop cx
pop di
pop ds
exit_28:
iret
newint28 endp
di28 dw 0
ds28 dw 0
dopopup proc near
cli ;no interrupts now!!!
or word ptr STATUS,TSRACTIVE ;set active bit
mov ISSEG,ss ;save user's stack segment
mov ISPTR,sp ;... and stack pointer
;DS was saved in INT8 or INT28
mov ss,SSEG ;load TSR stack segment ...
mov sp,SPTR ;... and stack pointer
push bp ;save all registers except for
push bx ;...those saved by calling routine,
push dx ;...DS,DI,CX,AX are restored on exit
push si ;...from this procedure
push es
mov [di28],di ;save TSR pointer until after saving
mov [ds28],ds ;...Indos stack
mov di,sp ;destination is our stack
dec di
dec di ;back off current word
mov ax,ss ;move stack segment
mov es,ax ;...to extra segment
mov si,cs:dossptr ;source is DOS Indos Primary Stack
mov ds,cs:dossseg ;...and segment, of course
dec si ;point to last word on DOS stack
dec si
mov cx,40h ;stack size to save
mov ax,sp ;save current stack pointer ...
sub ax,cx ;...and make room to avoid
sub ax,cx ;...overwriting during REP
mov sp,ax ;...and put it back
std ;set the direction flag ...
rep movsw ;and move the 40 word stack
mov sp,di
cld ;direction flag back
mov di,cs:di28 ;get TSR pointer back
mov ds,cs:ds28
sti ;interrupts back on!!
getdta OLDDTA ;save current DTA
call getpsp ;get current PSP segment
mov OLDPSP,bx ;...returned in BX
mov bx,PSP ;set TSR's PSP in BX
call setpsp ;...and do it
setdta DTA
xor ax,ax
call setup_int ;replace with our handler
push ds ;save DS:DI for after popup
push di
mov ds,DSEG ;load user's data segment
call dword ptr cs:POPUP ;call the user routine!!
pop di ;restore ds:di for addressibility
pop ds
mov bx,OLDPSP ;replace interrupted PSP
call setpsp
setdta OLDDTA ;restore interrupted DTA
xor ax,ax
call restore_int ;restore interrupts as well
;terminate checking here!
cli ;no interrupts while manipulating stack
mov cx,40h ;stack size here
mov di28,di ;save TSR pointer until after saving
mov ds28,ds ;...Indos stack
mov ax,ss ;source is current stack
mov ds,ax
mov si,sp ;point to last word on our stack
inc si
inc si
mov es,cs:dossseg ;destination is dos stack
mov di,cs:dossptr
sub di,cx ;point backward to last used word
sub di,cx ;...on dos stack
cld
rep movsw
mov sp,si ;skip over moved words
mov di,cs:[di28] ;get TSR pointer back
mov ds,cs:[ds28]
pop es
pop si
pop dx
pop bx
pop bp
;
; ***************************************************************************
;
; CAUTION!!!! THE USER ROUTINE MUST RETURN SS:SP WITH THE SAME
; VALUES AS ON ENTRY. OTHER REGISTERS WILL BE RESTORED
; BY THIS ROUTINE.
;
; ***************************************************************************
;
back_popup:
mov ss,ISSEG ;restore user's stack segment
mov sp,ISPTR ;... and stack pointer
;DS will be restored in INT8 or INT28
and STATUS,NOT HOTKEYON+TSRACTIVE
;clear hot-key and inuse bits
sti ;enable interrupts again
dopopup_end:
ret
dopopup endp
newint13 proc far
pushf
or cs:intflags,ININT13
popf ;get back original flags
pushf ;simulate interrupt ...
call dword ptr cs:oldint13 ;do the original
pushf
and cs:intflags,NOT ININT13
popf
ret 2
newint13 endp
newint21 proc far
pushf
sti ;allow interrupts
cmp ah,63h ;max number
jg notme
push ax ;some INT21 functions must be left
push bx ;...alone. They either never return,
mov bx,offset dos21funcs ;...grab parameters from the stack
mov al,ah ;...or can be interrupted.
xlat cs:dos21funcs ;test function against table
or al,al ;wait for functions marked zero
pop bx ;these ,ust be left alone
pop ax
jz notme ;jump to original INT21
jmp short set_21
notme:
popf
jmp dword ptr cs:oldint21
set_21:
or cs:intflags,ININT21 ;say int21 is active
popf ;get original flags back
pushf ;save flags and all regs that
call dword ptr cs:oldint21 ;do the interrupt
sti
pushf ;save return registers
and cs:intflags,NOT ININT21 ;not active any more
popf ;they're back
ret 2 ;return with flags set
newint21 endp
error24 dw 0
newint24 proc far
pushf
mov cs:error24,di ;save the error
mov al,0
iret
newint24 endp
pop_routine proc far ;just prints a msg and gets out
lea dx,hello
mov ah,9
int 21h ; display copyright notice
ret
pop_routine endp
TSR_stack db 512 dup(0)
TSR_stack_end:
res_part: ; this is the end of my resident code so I can tell DOS
; how big I am
;
;
; ***************************************************************************
;
; Initialization Code -- load routine and point new int14
;
second_time db 0 ;flag used to test for odd-byte check
begin:
lea dx,cpyrt
mov ah,9
int 21h ; display copyright notice
call getpsp ;Current PSP returned in BX
mov PSP,bx
getdta DTA ;macro to get Disk Transfer Address
mov ax,ds
mov DSEG,ax ;save it
mov SSEG,ax ;save it here too!
mov word ptr POPUP+2,ax ;save it here three!
mov ax,offset TSR_stack_end
sub ax,2
mov SPTR,ax
mov SHIFTST,08h ;ALT-Key + ...
mov HOTKEY,2dh ;...'X' to pop up
mov word ptr POPUP,offset pop_routine
mov ax,3400h ;find the DOS Indos Byte
int 21h
;IF SOMEBODY HAS AT&T DOS 2.11, would you please try something?
;
;Move the label 'crit2' to the second location (where it is currently)
;commented out, and see how it works. There is still some dissension
;about where the critical byte actually is in that version of DOS!
crit2:
mov word ptr indosflag,bx ;offset returned in BX
mov word ptr indosflag+2,es ;segment returned in ES
mov dossseg,es ;this is also the DOS stack segment
mov word ptr doscriterr+2,es;as well as the segment for the critical flag
;crit2:
mov cx,2000h ;search for instruction: CMP [crit flag],00
mov ax,3e80h ;3e80 is opcode to search for
mov di,bx ;start search here
crit3:
repnz scasw ;search until a match is found
jnz no_crit_found ;couldn't find critical byte
;we're going to search for the
;address of the critical flag
;es:[di-2] now points to:
; CMP [crit flag],00
; JNZ ...
; MOV SP,indos stack address
mov al,byte ptr es:[di+5] ;MOV SP,xxxx
cmp al,0bch ;opcode for MOV SP
jne crit3 ;bad place. Sorry
mov ax,word ptr es:[di] ;here's the critical byte address
mov word ptr doscriterr,ax
mov ax,word ptr es:[di+6] ;...and here's the stack pointer
mov word ptr dossptr,ax
mov ax,1
jmp no_error
no_crit_found:
mov al,second_time ;did we already try odd bytes?
or al,al
jz crit_again ;nope ...
jmp bad_dos_version ;we tried!
crit_again:
mov second_time,1 ;set the flag
inc bx ;increment pointer (needed for AT&T
jmp crit2 ;DOS 2.11 and some others
no_error:
mov ax,1
call setup_int
lea dx,res_part ; load offset of top of code
add dx,15 ;round up
shr dx,1
shr dx,1
shr dx,1
shr dx,1 ; divide by 16 to get paragraphs
xor al,al ; no errors
mov ah,31h ; load terminate & stay resident code
int 21h
bad_dos_version:
lea dx,bad_dos_msg
mov ah,9
int 21h ; display error message
mov ax,4cffh ;exit with -1 return code
int 21h
code ends
end start